Problem 8

This question involves the use of simple linear regression on the Auto data set.

library(data.table)
library(tidyverse)
auto <- fread("../Assignment 1/Auto.csv")
auto$horsepower <- as.numeric(auto$horsepower)
Warning: NAs introduced by coercion

8a

Use the lm() function to perform a simple linear regression with mpg as the response and horsepower as the predictor. Use the summary() function to print the results. Comment on the output. For example:

lm <- lm(mpg ~ horsepower, data = auto)
lm

Call:
lm(formula = mpg ~ horsepower, data = auto)

Coefficients:
(Intercept)   horsepower  
    39.9359      -0.1578  
summary(lm)

Call:
lm(formula = mpg ~ horsepower, data = auto)

Residuals:
     Min       1Q   Median       3Q      Max 
-13.5710  -3.2592  -0.3435   2.7630  16.9240 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 39.935861   0.717499   55.66   <2e-16 ***
horsepower  -0.157845   0.006446  -24.49   <2e-16 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.906 on 390 degrees of freedom
  (5 observations deleted due to missingness)
Multiple R-squared:  0.6059,    Adjusted R-squared:  0.6049 
F-statistic: 599.7 on 1 and 390 DF,  p-value: < 2.2e-16

8a i

Is there a relationship between the predictor and the re- sponse?

Yes. After horsepower is converted to numeric, there is a relationship between horsepower and mpg.

8a ii

How strong is the relationship between the predictor and the response?

Very strong. The p-value is tiny.

8a iii

Is the relationship between the predictor and the response positive or negative?

Negative. As horsepower increases, mpg decreases.

8a iv

What is the predicted mpg associated with a horsepower of 98? What are the associated 95% confidence and prediction intervals?

predict(lm, auto)[98]
      98 
23.36216 
# confidence interval
predict(lm, auto, interval = "confidence")[98,]
     fit      lwr      upr 
23.36216 22.87497 23.84936 
# prediction interval
predict(lm, auto, interval = "prediction")[98,]
     fit      lwr      upr 
23.36216 13.70483 33.01950 

8b

Plot the response and the predictor. Use the abline() function to display the least squares regression line.

plot(auto$horsepower, auto$mpg)
abline(lm)

8c

Use the plot() function to produce diagnostic plots of the least squares regression fit. Comment on any problems you see with the fit.

plot(lm)

From the textbook, Figure 3.9: “Plots of residuals versus predicted (or fitted) values for the Auto data set. In each plot, the red line is a smooth fit to the residuals, intended to make it easier to identify a trend. Left: A linear regression of mpg on horsepower. A strong pattern in the residuals indicates non-linearity in the data. Right: A linear regression of mpg on horsepower and horsepower. There is little pattern in the residuals.

9

This question involves the use of multiple linear regression on the Auto data set.

9a

Produce a scatterplot matrix which includes all of the variables in the data set.

auto$name <- as.factor(auto$name)
pairs(auto)

9b

Compute the matrix of correlations between the variables using the function cor(). You will need to exclude the name variable, which is qualitative.

cor(auto[, -9])
                    mpg  cylinders displacement horsepower
mpg           1.0000000 -0.7762599   -0.8044430         NA
cylinders    -0.7762599  1.0000000    0.9509199         NA
displacement -0.8044430  0.9509199    1.0000000         NA
horsepower           NA         NA           NA          1
weight       -0.8317389  0.8970169    0.9331044         NA
acceleration  0.4222974 -0.5040606   -0.5441618         NA
year          0.5814695 -0.3467172   -0.3698041         NA
origin        0.5636979 -0.5649716   -0.6106643         NA
                 weight acceleration       year     origin
mpg          -0.8317389    0.4222974  0.5814695  0.5636979
cylinders     0.8970169   -0.5040606 -0.3467172 -0.5649716
displacement  0.9331044   -0.5441618 -0.3698041 -0.6106643
horsepower           NA           NA         NA         NA
weight        1.0000000   -0.4195023 -0.3079004 -0.5812652
acceleration -0.4195023    1.0000000  0.2829009  0.2100836
year         -0.3079004    0.2829009  1.0000000  0.1843141
origin       -0.5812652    0.2100836  0.1843141  1.0000000

9c

Use the lm() function to perform a multiple linear regression with mpg as the response and all other variables except name as the predictors. Use the summary() function to print the results. Comment on the output. For instance:

lm <- lm(mpg ~ cylinders + displacement + horsepower + weight + acceleration + year + origin, auto)
lm

Call:
lm(formula = mpg ~ cylinders + displacement + horsepower + weight + 
    acceleration + year + origin, data = auto)

Coefficients:
 (Intercept)     cylinders  displacement    horsepower  
  -17.218435     -0.493376      0.019896     -0.016951  
      weight  acceleration          year        origin  
   -0.006474      0.080576      0.750773      1.426140  
summary(lm)

Call:
lm(formula = mpg ~ cylinders + displacement + horsepower + weight + 
    acceleration + year + origin, data = auto)

Residuals:
    Min      1Q  Median      3Q     Max 
-9.5903 -2.1565 -0.1169  1.8690 13.0604 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -17.218435   4.644294  -3.707  0.00024 ***
cylinders     -0.493376   0.323282  -1.526  0.12780    
displacement   0.019896   0.007515   2.647  0.00844 ** 
horsepower    -0.016951   0.013787  -1.230  0.21963    
weight        -0.006474   0.000652  -9.929  < 2e-16 ***
acceleration   0.080576   0.098845   0.815  0.41548    
year           0.750773   0.050973  14.729  < 2e-16 ***
origin         1.426141   0.278136   5.127 4.67e-07 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.328 on 384 degrees of freedom
  (5 observations deleted due to missingness)
Multiple R-squared:  0.8215,    Adjusted R-squared:  0.8182 
F-statistic: 252.4 on 7 and 384 DF,  p-value: < 2.2e-16

9c i

Is there a relationship between the predictors and the re- sponse?

There is a relationship between mpg and displacement, weight, year, and origin.

9c ii

Which predictors appear to have a statistically significant relationship to the response?

There is a relationship between mpg and displacement, weight, year, and origin.

9c iii

What does the coefficient for the year variable suggest?

This suggests that the mpg increases alongside the year. (Cars become more efficient over time).

9d

Use the plot() function to produce diagnostic plots of the linear regression fit. Comment on any problems you see with the fit. Do the residual plots suggest any unusually large outliers? Does the leverage plot identify any observations with unusually high leverage?

plot(lm)

There are a decent amount of outliers among the dataset. There are a few observations with strangely high leverage.

9e

Use the * and : symbols to fit linear regression models with interaction effects. Do any interactions appear to be statistically significant?

summary(lm(mpg ~ cylinders * displacement + horsepower:weight, auto))

Call:
lm(formula = mpg ~ cylinders * displacement + horsepower:weight, 
    data = auto)

Residuals:
     Min       1Q   Median       3Q      Max 
-15.8087  -2.2841  -0.5424   2.1259  17.5877 

Coefficients:
                         Estimate Std. Error t value
(Intercept)             5.524e+01  2.384e+00  23.167
cylinders              -3.831e+00  5.339e-01  -7.176
displacement           -1.388e-01  1.511e-02  -9.184
cylinders:displacement  1.923e-02  2.171e-03   8.857
horsepower:weight      -2.231e-05  2.961e-06  -7.533
                       Pr(>|t|)    
(Intercept)             < 2e-16 ***
cylinders              3.68e-12 ***
displacement            < 2e-16 ***
cylinders:displacement  < 2e-16 ***
horsepower:weight      3.54e-13 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.164 on 387 degrees of freedom
  (5 observations deleted due to missingness)
Multiple R-squared:  0.7182,    Adjusted R-squared:  0.7153 
F-statistic: 246.6 on 4 and 387 DF,  p-value: < 2.2e-16

I guessed and it turns out that my suspicions were correct. cylinders:diplacement and horsepower:weight were significant.

9f

Try a few different transformations of the variables, such as \(log(X)\), \(\sqrt{X}\), \(X^2\). Comment on your findings.

summary(lm(log(mpg) ~ cylinders^2, auto))

Call:
lm(formula = log(mpg) ~ cylinders^2, data = auto)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.61694 -0.12149 -0.00995  0.12358  0.62573 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  4.002754   0.032379  123.62   <2e-16 ***
cylinders   -0.165149   0.005664  -29.16   <2e-16 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1918 on 395 degrees of freedom
Multiple R-squared:  0.6828,    Adjusted R-squared:  0.682 
F-statistic: 850.3 on 1 and 395 DF,  p-value: < 2.2e-16
summary(lm(log(mpg) ~ cylinders^2 + log(horsepower)^2:sqrt(weight), auto))

Call:
lm(formula = log(mpg) ~ cylinders^2 + log(horsepower)^2:sqrt(weight), 
    data = auto)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.47818 -0.10004 -0.00615  0.10030  0.51869 

Coefficients:
                               Estimate Std. Error t value
(Intercept)                   4.4881118  0.0421172 106.563
cylinders                    -0.0211598  0.0107477  -1.969
log(horsepower):sqrt(weight) -0.0050924  0.0003451 -14.756
                             Pr(>|t|)    
(Intercept)                    <2e-16 ***
cylinders                      0.0497 *  
log(horsepower):sqrt(weight)   <2e-16 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1535 on 389 degrees of freedom
  (5 observations deleted due to missingness)
Multiple R-squared:  0.7972,    Adjusted R-squared:  0.7961 
F-statistic: 764.4 on 2 and 389 DF,  p-value: < 2.2e-16

I’m a little surprised that the regressions didn’t break as easily as I thought they would with some basic transformations.

10

This question should be answered using the Carseats data set.

carseats <- ISLR2::Carseats

10a

Fit a multiple regression model to predict Sales using Price, Urban, and US.

lm <- lm(Sales ~ Price + Urban + US, carseats)
lm

Call:
lm(formula = Sales ~ Price + Urban + US, data = carseats)

Coefficients:
(Intercept)        Price     UrbanYes        USYes  
   13.04347     -0.05446     -0.02192      1.20057  
summary(lm)

Call:
lm(formula = Sales ~ Price + Urban + US, data = carseats)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.9206 -1.6220 -0.0564  1.5786  7.0581 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 13.043469   0.651012  20.036  < 2e-16 ***
Price       -0.054459   0.005242 -10.389  < 2e-16 ***
UrbanYes    -0.021916   0.271650  -0.081    0.936    
USYes        1.200573   0.259042   4.635 4.86e-06 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.472 on 396 degrees of freedom
Multiple R-squared:  0.2393,    Adjusted R-squared:  0.2335 
F-statistic: 41.52 on 3 and 396 DF,  p-value: < 2.2e-16

10b

Provide an interpretation of each coefficient in the model. Be careful—some of the variables in the model are qualitative!

As Price increases by 1, Sales decrease by \(.054459\) When Urban is Yes, Sales decrease by \(.021916\) (but this isn’t significant) When US is Yes, Sales increases by \(1.021916\)

10c

Write out the model in equation form, being careful to handle the qualitative variables properly.

\(\textrm{Sales}=13.04-.05\textrm{Price}-(.02\textrm{Urban}_{\textrm{Yes}})+(1.20\textrm{US}_{\textrm{Yes}})\)

10d

For which of the predictors can you reject the null hypothesis \(H0:β_j=0\) ?

Price and USYes are significant enough with a p-value less than 0.05 so we are 95% confident that they are significant.

10e

On the basis of your response to the previous question, fit a smaller model that only uses the predictors for which there is evidence of association with the outcome.

lm <- lm(Sales ~ Price + US, carseats)
lm

Call:
lm(formula = Sales ~ Price + US, data = carseats)

Coefficients:
(Intercept)        Price        USYes  
   13.03079     -0.05448      1.19964  
summary(lm)

Call:
lm(formula = Sales ~ Price + US, data = carseats)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.9269 -1.6286 -0.0574  1.5766  7.0515 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 13.03079    0.63098  20.652  < 2e-16 ***
Price       -0.05448    0.00523 -10.416  < 2e-16 ***
USYes        1.19964    0.25846   4.641 4.71e-06 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.469 on 397 degrees of freedom
Multiple R-squared:  0.2393,    Adjusted R-squared:  0.2354 
F-statistic: 62.43 on 2 and 397 DF,  p-value: < 2.2e-16

10f

How well do the models in (a) and (e) fit the data?

The model in (e) fits much better than the one in (a) because it only has significant variables.

10g

Using the model from (e), obtain \(95\%\) confidence intervals for the coefficient(s).

confint(lm)
                  2.5 %      97.5 %
(Intercept) 11.79032020 14.27126531
Price       -0.06475984 -0.04419543
USYes        0.69151957  1.70776632

10h

Is there evidence of outliers or high leverage observations in the model from (e)?

par(mfrow = c(2,2))
plot(lm)

There are a few points that look to be outside the normal range. Points 51, 69, and 377 seem to be outliers and points 26, 50, and 368 seem to have high leverage. I’m not worried about them because there are only three in a good-sized dataset.

4

From the data available at http://www.stat.ufl.edu/~winner/datasets.html, obtain the data on “Fibre Diameters and Breaking Strenghs for Nextel 610 Fibres.” (please note that there is a typo on the website. It should be Strength and not Strengh) According to the description available there, the expectation is that the log of breaking strength of the fibre should be negatively and linearly related to diameter. (Note log here means natural log if not specified.)

dt <- fread("fibre.csv")
colnames(dt) <- c("stren", "diam")
head(dt)

4a

Produce a scatter plot of breaking strength against diameter.

plot(dt$diam, dt$stren)

4b

Produce a scatter plot of the log of breaking strength against diameter.

dt$logStren <- log(dt$stren)
plot(dt$logStren, dt$diam)

4c

Produce a scatter plot of the log of breaking strength against the log of diameter.

dt$logDiam <- log(dt$diam)
plot(dt$logStren, dt$logDiam)

4d

Regress breaking strength on diameter.

lm <- lm(stren ~ diam, data = dt)
lm

Call:
lm(formula = stren ~ diam, data = dt)

Coefficients:
(Intercept)         diam  
     5312.8       -197.7  
summary(lm)

Call:
lm(formula = stren ~ diam, data = dt)

Residuals:
    Min      1Q  Median      3Q     Max 
-603.46 -246.10   -6.76  223.64 1047.22 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  5312.78    1040.41   5.106 5.61e-06 ***
diam         -197.73      91.91  -2.151   0.0365 *  
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 335.7 on 48 degrees of freedom
Multiple R-squared:  0.08794,   Adjusted R-squared:  0.06894 
F-statistic: 4.628 on 1 and 48 DF,  p-value: 0.03651

4e

Regress the log of breaking strength on diameter.

lm <- lm(logStren ~ diam, data = dt)
lm

Call:
lm(formula = logStren ~ diam, data = dt)

Coefficients:
(Intercept)         diam  
    8.76091     -0.06504  
summary(lm)

Call:
lm(formula = logStren ~ diam, data = dt)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.211992 -0.075119  0.003561  0.076367  0.293763 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  8.76091    0.33575  26.094   <2e-16 ***
diam        -0.06504    0.02966  -2.193   0.0332 *  
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1083 on 48 degrees of freedom
Multiple R-squared:  0.09105,   Adjusted R-squared:  0.07211 
F-statistic: 4.808 on 1 and 48 DF,  p-value: 0.0332

4f

Regress the log of breaking strength on the log of diameter.

lm <- lm(logStren ~ logDiam, data = dt)
lm

Call:
lm(formula = logStren ~ logDiam, data = dt)

Coefficients:
(Intercept)      logDiam  
     9.8328      -0.7454  
summary(lm)

Call:
lm(formula = logStren ~ logDiam, data = dt)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.21123 -0.07610  0.00396  0.07673  0.29398 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   9.8328     0.8209  11.978 4.99e-16 ***
logDiam      -0.7454     0.3385  -2.202   0.0325 *  
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1083 on 48 degrees of freedom
Multiple R-squared:  0.09174,   Adjusted R-squared:  0.07282 
F-statistic: 4.848 on 1 and 48 DF,  p-value: 0.03251

5

From the data available at http://www.stat.ufl.edu/~winner/datasets.html, obtain the data on “Variables associated with Permeability and Porosity of Rocks”

dt <- fread("rocks.csv")
colnames(dt) <- c("type", "density", "porosity", "logPermeability", "residue", "carbonate", "aGrain", "aSD", "bGrain", "bSD", "calcite", "dolomite")
head(dt)

5a

Fit a multiple regression model to predict porosity. Please provide a clean model with only significant variables. Interpret your model results and diagnostics.

lm <- lm(porosity ~ ., data = dt)
lmSumm <- summary(lm)
coefs <- coef(lmSumm)[-1,4] <= .05

# This prunes the regression until only significant variables remain
while(length(coefs) != sum(coefs)) {
  form <- paste("porosity ~", paste(names(coefs[coefs]), "+", collapse = " "), collapse = " ")
  form <- substr(form, 1, nchar(form) - 2)
  form
  lm <- lm(formula = form, data = dt)
  lmSumm <- summary(lm)
  coefs <- coef(lmSumm)[-1,4] <= .05
}
lm

Call:
lm(formula = form, data = dt)

Coefficients:
    (Intercept)  logPermeability  
          6.240            2.666  
lmSumm

Call:
lm(formula = form, data = dt)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.1522 -1.0096 -0.2271  0.3610  5.8290 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)   
(Intercept)        6.240      2.046   3.050  0.00485 **
logPermeability    2.666      1.222   2.181  0.03740 * 
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.689 on 29 degrees of freedom
Multiple R-squared:  0.141, Adjusted R-squared:  0.1113 
F-statistic: 4.759 on 1 and 29 DF,  p-value: 0.0374
par(mfrow = c(2,2))
plot(lm)

5b

Fit a multiple regression model to predict log(permeability). Please provide a clean model with only significant variables. Interpret your model results and diagnostics.

lm <- lm(logPermeability ~ ., data = dt)
lmSumm <- summary(lm)
coefs <- coef(lmSumm)[-1,4] <= .05

# This prunes the regression until only significant variables remain
while(length(coefs) != sum(coefs)) {
  form <- paste("logPermeability ~", paste(names(coefs[coefs]), "+", collapse = " "), collapse = " ")
  form <- substr(form, 1, nchar(form) - 2)
  form
  lm <- lm(formula = form, data = dt)
  lmSumm <- summary(lm)
  coefs <- coef(lmSumm)[-1,4] <= .05
}
lm

Call:
lm(formula = form, data = dt)

Coefficients:
(Intercept)     porosity       aGrain       bGrain  
  -0.448085     0.063658     0.897464    -0.994242  
    calcite  
   0.003091  
lmSumm

Call:
lm(formula = form, data = dt)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.58844 -0.06918  0.02635  0.09975  0.40127 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)   
(Intercept) -0.448085   0.499277  -0.897  0.37771   
porosity     0.063658   0.023650   2.692  0.01227 * 
aGrain       0.897464   0.430584   2.084  0.04710 * 
bGrain      -0.994242   0.431684  -2.303  0.02952 * 
calcite      0.003091   0.001066   2.899  0.00751 **
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2019 on 26 degrees of freedom
Multiple R-squared:  0.4452,    Adjusted R-squared:  0.3598 
F-statistic: 5.216 on 4 and 26 DF,  p-value: 0.003204
par(mfrow = c(2,2))
plot(lm)

LS0tCnRpdGxlOiAiQXNzaWdubWVudCAyIgphdXRob3I6ICJHdXMgTGlwa2luIH4gZ2xpcGtpbjY3MzdAZmxvcmlkYXBvbHkuZWR1IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAotLS0KCiMgUHJvYmxlbSA4Cj4gVGhpcyBxdWVzdGlvbiBpbnZvbHZlcyB0aGUgdXNlIG9mIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBvbiB0aGUgQXV0byBkYXRhIHNldC4KCmBgYHtyfQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkodGlkeXZlcnNlKQphdXRvIDwtIGZyZWFkKCIuLi9Bc3NpZ25tZW50IDEvQXV0by5jc3YiKQphdXRvJGhvcnNlcG93ZXIgPC0gYXMubnVtZXJpYyhhdXRvJGhvcnNlcG93ZXIpCmBgYAoKCiMjIDhhCj4gVXNlIHRoZSBgbG0oKWAgZnVuY3Rpb24gdG8gcGVyZm9ybSBhIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiB3aXRoIGBtcGdgIGFzIHRoZSByZXNwb25zZSBhbmQgYGhvcnNlcG93ZXJgIGFzIHRoZSBwcmVkaWN0b3IuIFVzZSB0aGUgYHN1bW1hcnkoKWAgZnVuY3Rpb24gdG8gcHJpbnQgdGhlIHJlc3VsdHMuIENvbW1lbnQgb24gdGhlIG91dHB1dC4gRm9yIGV4YW1wbGU6CgpgYGB7cn0KbG0gPC0gbG0obXBnIH4gaG9yc2Vwb3dlciwgZGF0YSA9IGF1dG8pCmxtCnN1bW1hcnkobG0pCmBgYAoKCiMjIyA4YSBpCj4gSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgcHJlZGljdG9yIGFuZCB0aGUgcmUtIHNwb25zZT8KClllcy4gQWZ0ZXIgaG9yc2Vwb3dlciBpcyBjb252ZXJ0ZWQgdG8gbnVtZXJpYywgdGhlcmUgaXMgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBgaG9yc2Vwb3dlcmAgYW5kIGBtcGdgLgoKIyMjIDhhIGlpCj4gSG93IHN0cm9uZyBpcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHByZWRpY3RvciBhbmQgdGhlIHJlc3BvbnNlPwoKVmVyeSBzdHJvbmcuIFRoZSBwLXZhbHVlIGlzIHRpbnkuCgojIyMgOGEgaWlpCj4gSXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBwcmVkaWN0b3IgYW5kIHRoZSByZXNwb25zZSBwb3NpdGl2ZSBvciBuZWdhdGl2ZT8KCk5lZ2F0aXZlLiBBcyBgaG9yc2Vwb3dlcmAgaW5jcmVhc2VzLCBgbXBnYCBkZWNyZWFzZXMuCgojIyMgOGEgaXYKPiBXaGF0IGlzIHRoZSBwcmVkaWN0ZWQgYG1wZ2AgYXNzb2NpYXRlZCB3aXRoIGEgYGhvcnNlcG93ZXJgIG9mIDk4PyBXaGF0IGFyZSB0aGUgYXNzb2NpYXRlZCA5NSUgY29uZmlkZW5jZSBhbmQgcHJlZGljdGlvbiBpbnRlcnZhbHM/CgpgYGB7cn0KcHJlZGljdChsbSwgYXV0bylbOThdCiMgY29uZmlkZW5jZSBpbnRlcnZhbApwcmVkaWN0KGxtLCBhdXRvLCBpbnRlcnZhbCA9ICJjb25maWRlbmNlIilbOTgsXQojIHByZWRpY3Rpb24gaW50ZXJ2YWwKcHJlZGljdChsbSwgYXV0bywgaW50ZXJ2YWwgPSAicHJlZGljdGlvbiIpWzk4LF0KYGBgCgoKIyMgOGIKPiBQbG90IHRoZSByZXNwb25zZSBhbmQgdGhlIHByZWRpY3Rvci4gVXNlIHRoZSBgYWJsaW5lKClgIGZ1bmN0aW9uIHRvIGRpc3BsYXkgdGhlIGxlYXN0IHNxdWFyZXMgcmVncmVzc2lvbiBsaW5lLgoKYGBge3J9CnBsb3QoYXV0byRob3JzZXBvd2VyLCBhdXRvJG1wZykKYWJsaW5lKGxtKQpgYGAKCgojIyA4Ywo+IFVzZSB0aGUgYHBsb3QoKWAgZnVuY3Rpb24gdG8gcHJvZHVjZSBkaWFnbm9zdGljIHBsb3RzIG9mIHRoZSBsZWFzdCBzcXVhcmVzIHJlZ3Jlc3Npb24gZml0LiBDb21tZW50IG9uIGFueSBwcm9ibGVtcyB5b3Ugc2VlIHdpdGggdGhlIGZpdC4KCmBgYHtyfQpwbG90KGxtKQpgYGAKCkZyb20gdGhlIHRleHRib29rLCBGaWd1cmUgMy45OiAiKlBsb3RzIG9mIHJlc2lkdWFscyB2ZXJzdXMgcHJlZGljdGVkIChvciBmaXR0ZWQpIHZhbHVlcyBmb3IgdGhlIEF1dG8gZGF0YSBzZXQuIEluIGVhY2ggcGxvdCwgdGhlIHJlZCBsaW5lIGlzIGEgc21vb3RoIGZpdCB0byB0aGUgcmVzaWR1YWxzLCBpbnRlbmRlZCB0byBtYWtlIGl0IGVhc2llciB0byBpZGVudGlmeSBhIHRyZW5kLiBMZWZ0OiBBIGxpbmVhciByZWdyZXNzaW9uIG9mIGBtcGdgIG9uIGBob3JzZXBvd2VyYC4gQSBzdHJvbmcgcGF0dGVybiBpbiB0aGUgcmVzaWR1YWxzIGluZGljYXRlcyBub24tbGluZWFyaXR5IGluIHRoZSBkYXRhLiBSaWdodDogQSBsaW5lYXIgcmVncmVzc2lvbiBvZiBgbXBnYCBvbiBgaG9yc2Vwb3dlcmAgYW5kIGBob3JzZXBvd2VyYC4gVGhlcmUgaXMgbGl0dGxlIHBhdHRlcm4gaW4gdGhlIHJlc2lkdWFscy4qIgoKIyA5Cj4gVGhpcyBxdWVzdGlvbiBpbnZvbHZlcyB0aGUgdXNlIG9mIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIG9uIHRoZSBgQXV0b2AgZGF0YSBzZXQuCgojIyA5YQo+IFByb2R1Y2UgYSBzY2F0dGVycGxvdCBtYXRyaXggd2hpY2ggaW5jbHVkZXMgYWxsIG9mIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0LgoKYGBge3J9CmF1dG8kbmFtZSA8LSBhcy5mYWN0b3IoYXV0byRuYW1lKQpwYWlycyhhdXRvKQpgYGAKCiMjIDliCj4gQ29tcHV0ZSB0aGUgbWF0cml4IG9mIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgdXNpbmcgdGhlIGZ1bmN0aW9uIGBjb3IoKWAuIFlvdSB3aWxsIG5lZWQgdG8gZXhjbHVkZSB0aGUgYG5hbWVgIHZhcmlhYmxlLCB3aGljaCBpcyBxdWFsaXRhdGl2ZS4KCmBgYHtyfQpjb3IoYXV0b1ssIC05XSkKYGBgCgojIyA5Ywo+IFVzZSB0aGUgYGxtKClgIGZ1bmN0aW9uIHRvIHBlcmZvcm0gYSBtdWx0aXBsZSBsaW5lYXIgcmVncmVzc2lvbiB3aXRoIGBtcGdgIGFzIHRoZSByZXNwb25zZSBhbmQgYWxsIG90aGVyIHZhcmlhYmxlcyBleGNlcHQgYG5hbWVgIGFzIHRoZSBwcmVkaWN0b3JzLiBVc2UgdGhlIGBzdW1tYXJ5KClgIGZ1bmN0aW9uIHRvIHByaW50IHRoZSByZXN1bHRzLiBDb21tZW50IG9uIHRoZSBvdXRwdXQuIEZvciBpbnN0YW5jZToKCmBgYHtyfQpsbSA8LSBsbShtcGcgfiBjeWxpbmRlcnMgKyBkaXNwbGFjZW1lbnQgKyBob3JzZXBvd2VyICsgd2VpZ2h0ICsgYWNjZWxlcmF0aW9uICsgeWVhciArIG9yaWdpbiwgYXV0bykKbG0Kc3VtbWFyeShsbSkKYGBgCgoKIyMjIDljIGkKPiBJcyB0aGVyZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBwcmVkaWN0b3JzIGFuZCB0aGUgcmUtIHNwb25zZT8KClRoZXJlIGlzIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gYG1wZ2AgYW5kIGBkaXNwbGFjZW1lbnRgLCBgd2VpZ2h0YCwgYHllYXJgLCBhbmQgYG9yaWdpbmAuCgojIyMgOWMgaWkKPiBXaGljaCBwcmVkaWN0b3JzIGFwcGVhciB0byBoYXZlIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgdG8gdGhlIHJlc3BvbnNlPwoKVGhlcmUgaXMgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBgbXBnYCBhbmQgYGRpc3BsYWNlbWVudGAsIGB3ZWlnaHRgLCBgeWVhcmAsIGFuZCBgb3JpZ2luYC4KCiMjIyA5YyBpaWkKPiBXaGF0IGRvZXMgdGhlIGNvZWZmaWNpZW50IGZvciB0aGUgYHllYXJgIHZhcmlhYmxlIHN1Z2dlc3Q/CgpUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIGBtcGdgIGluY3JlYXNlcyBhbG9uZ3NpZGUgdGhlIGB5ZWFyYC4gKENhcnMgYmVjb21lIG1vcmUgZWZmaWNpZW50IG92ZXIgdGltZSkuCgojIyA5ZAo+IFVzZSB0aGUgYHBsb3QoKWAgZnVuY3Rpb24gdG8gcHJvZHVjZSBkaWFnbm9zdGljIHBsb3RzIG9mIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBmaXQuIENvbW1lbnQgb24gYW55IHByb2JsZW1zIHlvdSBzZWUgd2l0aCB0aGUgZml0LiBEbyB0aGUgcmVzaWR1YWwgcGxvdHMgc3VnZ2VzdCBhbnkgdW51c3VhbGx5IGxhcmdlIG91dGxpZXJzPyBEb2VzIHRoZSBsZXZlcmFnZSBwbG90IGlkZW50aWZ5IGFueSBvYnNlcnZhdGlvbnMgd2l0aCB1bnVzdWFsbHkgaGlnaCBsZXZlcmFnZT8KCmBgYHtyfQpwbG90KGxtKQpgYGAKClRoZXJlIGFyZSBhIGRlY2VudCBhbW91bnQgb2Ygb3V0bGllcnMgYW1vbmcgdGhlIGRhdGFzZXQuIFRoZXJlIGFyZSBhIGZldyBvYnNlcnZhdGlvbnMgd2l0aCBzdHJhbmdlbHkgaGlnaCBsZXZlcmFnZS4KCiMjIDllCj4gVXNlIHRoZSBgKmAgYW5kIGA6YCBzeW1ib2xzIHRvIGZpdCBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbHMgd2l0aCBpbnRlcmFjdGlvbiBlZmZlY3RzLiBEbyBhbnkgaW50ZXJhY3Rpb25zIGFwcGVhciB0byBiZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50PwoKYGBge3J9CnN1bW1hcnkobG0obXBnIH4gY3lsaW5kZXJzICogZGlzcGxhY2VtZW50ICsgaG9yc2Vwb3dlcjp3ZWlnaHQsIGF1dG8pKQpgYGAKCkkgZ3Vlc3NlZCBhbmQgaXQgdHVybnMgb3V0IHRoYXQgbXkgc3VzcGljaW9ucyB3ZXJlIGNvcnJlY3QuIGBjeWxpbmRlcnM6ZGlwbGFjZW1lbnRgIGFuZCBgaG9yc2Vwb3dlcjp3ZWlnaHRgIHdlcmUgc2lnbmlmaWNhbnQuCgojIyA5Zgo+IFRyeSBhIGZldyBkaWZmZXJlbnQgdHJhbnNmb3JtYXRpb25zIG9mIHRoZSB2YXJpYWJsZXMsIHN1Y2ggYXMgJGxvZyhYKSQsICRcc3FydHtYfSQsICRYXjIkLiBDb21tZW50IG9uIHlvdXIgZmluZGluZ3MuCgpgYGB7cn0Kc3VtbWFyeShsbShsb2cobXBnKSB+IGN5bGluZGVyc14yLCBhdXRvKSkKc3VtbWFyeShsbShsb2cobXBnKSB+IGN5bGluZGVyc14yICsgbG9nKGhvcnNlcG93ZXIpXjI6c3FydCh3ZWlnaHQpLCBhdXRvKSkKYGBgCgpJJ20gYSBsaXR0bGUgc3VycHJpc2VkIHRoYXQgdGhlIHJlZ3Jlc3Npb25zIGRpZG4ndCBicmVhayBhcyBlYXNpbHkgYXMgSSB0aG91Z2h0IHRoZXkgd291bGQgd2l0aCBzb21lIGJhc2ljIHRyYW5zZm9ybWF0aW9ucy4KCiMgMTAKPiBUaGlzIHF1ZXN0aW9uIHNob3VsZCBiZSBhbnN3ZXJlZCB1c2luZyB0aGUgYENhcnNlYXRzYCBkYXRhIHNldC4KCmBgYHtyfQpjYXJzZWF0cyA8LSBJU0xSMjo6Q2Fyc2VhdHMKYGBgCgoKIyMgMTBhCj4gRml0IGEgbXVsdGlwbGUgcmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IGBTYWxlc2AgdXNpbmcgYFByaWNlYCwgYFVyYmFuYCwgYW5kIGBVUy5gCgpgYGB7cn0KbG0gPC0gbG0oU2FsZXMgfiBQcmljZSArIFVyYmFuICsgVVMsIGNhcnNlYXRzKQpsbQpzdW1tYXJ5KGxtKQpgYGAKCiMjIDEwYgo+IFByb3ZpZGUgYW4gaW50ZXJwcmV0YXRpb24gb2YgZWFjaCBjb2VmZmljaWVudCBpbiB0aGUgbW9kZWwuIEJlIGNhcmVmdWzigJRzb21lIG9mIHRoZSB2YXJpYWJsZXMgaW4gdGhlIG1vZGVsIGFyZSBxdWFsaXRhdGl2ZSEKCkFzIGBQcmljZWAgaW5jcmVhc2VzIGJ5IDEsIGBTYWxlc2AgZGVjcmVhc2UgYnkgJC4wNTQ0NTkkCldoZW4gYFVyYmFuYCBpcyBgWWVzYCwgYFNhbGVzYCBkZWNyZWFzZSBieSAkLjAyMTkxNiQgKGJ1dCB0aGlzIGlzbid0IHNpZ25pZmljYW50KQpXaGVuIGBVU2AgaXMgYFllc2AsIGBTYWxlc2AgaW5jcmVhc2VzIGJ5ICQxLjAyMTkxNiQKCiMjIDEwYwo+IFdyaXRlIG91dCB0aGUgbW9kZWwgaW4gZXF1YXRpb24gZm9ybSwgYmVpbmcgY2FyZWZ1bCB0byBoYW5kbGUgdGhlIHF1YWxpdGF0aXZlIHZhcmlhYmxlcyBwcm9wZXJseS4KCiRcdGV4dHJte1NhbGVzfT0xMy4wNC0uMDVcdGV4dHJte1ByaWNlfS0oLjAyXHRleHRybXtVcmJhbn1fe1x0ZXh0cm17WWVzfX0pKygxLjIwXHRleHRybXtVU31fe1x0ZXh0cm17WWVzfX0pJAoKIyMgMTBkCj4gRm9yIHdoaWNoIG9mIHRoZSBwcmVkaWN0b3JzIGNhbiB5b3UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgJEgwOs6yX2o9MCQgPwoKYFByaWNlYCBhbmQgYFVTWWVzYCBhcmUgc2lnbmlmaWNhbnQgZW5vdWdoIHdpdGggYSBwLXZhbHVlIGxlc3MgdGhhbiAwLjA1IHNvIHdlIGFyZSA5NSUgY29uZmlkZW50IHRoYXQgdGhleSBhcmUgc2lnbmlmaWNhbnQuCgojIyAxMGUKPiBPbiB0aGUgYmFzaXMgb2YgeW91ciByZXNwb25zZSB0byB0aGUgcHJldmlvdXMgcXVlc3Rpb24sIGZpdCBhIHNtYWxsZXIgbW9kZWwgdGhhdCBvbmx5IHVzZXMgdGhlIHByZWRpY3RvcnMgZm9yIHdoaWNoIHRoZXJlIGlzIGV2aWRlbmNlIG9mIGFzc29jaWF0aW9uIHdpdGggdGhlIG91dGNvbWUuCgpgYGB7cn0KbG0gPC0gbG0oU2FsZXMgfiBQcmljZSArIFVTLCBjYXJzZWF0cykKbG0Kc3VtbWFyeShsbSkKYGBgCgojIyAxMGYKPiBIb3cgd2VsbCBkbyB0aGUgbW9kZWxzIGluIChhKSBhbmQgKGUpIGZpdCB0aGUgZGF0YT8KClRoZSBtb2RlbCBpbiAoZSkgZml0cyBtdWNoIGJldHRlciB0aGFuIHRoZSBvbmUgaW4gKGEpIGJlY2F1c2UgaXQgb25seSBoYXMgc2lnbmlmaWNhbnQgdmFyaWFibGVzLiAKCiMjIDEwZwo+IFVzaW5nIHRoZSBtb2RlbCBmcm9tIChlKSwgb2J0YWluICQ5NVwlJCBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIGNvZWZmaWNpZW50KHMpLgoKYGBge3J9CmNvbmZpbnQobG0pCmBgYAoKIyMgMTBoCj4gSXMgdGhlcmUgZXZpZGVuY2Ugb2Ygb3V0bGllcnMgb3IgaGlnaCBsZXZlcmFnZSBvYnNlcnZhdGlvbnMgaW4gdGhlIG1vZGVsIGZyb20gKGUpPwoKYGBge3J9CnBhcihtZnJvdyA9IGMoMiwyKSkKcGxvdChsbSkKYGBgCgpUaGVyZSBhcmUgYSBmZXcgcG9pbnRzIHRoYXQgbG9vayB0byBiZSBvdXRzaWRlIHRoZSBub3JtYWwgcmFuZ2UuIFBvaW50cyA1MSwgNjksIGFuZCAzNzcgc2VlbSB0byBiZSBvdXRsaWVycyBhbmQgcG9pbnRzIDI2LCA1MCwgYW5kIDM2OCBzZWVtIHRvIGhhdmUgaGlnaCBsZXZlcmFnZS4gSSdtIG5vdCB3b3JyaWVkIGFib3V0IHRoZW0gYmVjYXVzZSB0aGVyZSBhcmUgb25seSB0aHJlZSBpbiBhIGdvb2Qtc2l6ZWQgZGF0YXNldC4gCgojIDQKPiBGcm9tIHRoZSBkYXRhIGF2YWlsYWJsZSBhdCBbaHR0cDovL3d3dy5zdGF0LnVmbC5lZHUvfndpbm5lci9kYXRhc2V0cy5odG1sXShodHRwOi8vd3d3LnN0YXQudWZsLmVkdS9+d2lubmVyL2RhdGFzZXRzLmh0bWwpLCBvYnRhaW4gdGhlIGRhdGEgb24g4oCcRmlicmUgRGlhbWV0ZXJzIGFuZCBCcmVha2luZyBTdHJlbmdocyBmb3IgTmV4dGVsIDYxMCBGaWJyZXMu4oCdIChwbGVhc2Ugbm90ZSB0aGF0IHRoZXJlIGlzIGEgdHlwbyBvbiB0aGUgd2Vic2l0ZS4gSXQgc2hvdWxkIGJlIFN0cmVuZ3RoIGFuZCBub3QgU3RyZW5naCkgQWNjb3JkaW5nIHRvIHRoZSBkZXNjcmlwdGlvbiBhdmFpbGFibGUgdGhlcmUsIHRoZSBleHBlY3RhdGlvbiBpcyB0aGF0IHRoZSBsb2cgb2YgYnJlYWtpbmcgc3RyZW5ndGggb2YgdGhlIGZpYnJlIHNob3VsZCBiZSBuZWdhdGl2ZWx5IGFuZCBsaW5lYXJseSByZWxhdGVkIHRvIGRpYW1ldGVyLiAoTm90ZSBsb2cgaGVyZSBtZWFucyBuYXR1cmFsIGxvZyBpZiBub3Qgc3BlY2lmaWVkLikKCmBgYHtyfQpkdCA8LSBmcmVhZCgiZmlicmUuY3N2IikKY29sbmFtZXMoZHQpIDwtIGMoInN0cmVuIiwgImRpYW0iKQpoZWFkKGR0KQpgYGAKCgojIyA0YQo+IFByb2R1Y2UgYSBzY2F0dGVyIHBsb3Qgb2YgYnJlYWtpbmcgc3RyZW5ndGggYWdhaW5zdCBkaWFtZXRlci4KCmBgYHtyfQpwbG90KGR0JGRpYW0sIGR0JHN0cmVuKQpgYGAKCiMjIDRiCj4gUHJvZHVjZSBhIHNjYXR0ZXIgcGxvdCBvZiB0aGUgbG9nIG9mIGJyZWFraW5nIHN0cmVuZ3RoIGFnYWluc3QgZGlhbWV0ZXIuIAoKYGBge3J9CmR0JGxvZ1N0cmVuIDwtIGxvZyhkdCRzdHJlbikKcGxvdChkdCRsb2dTdHJlbiwgZHQkZGlhbSkKYGBgCgojIyA0YyAKPiBQcm9kdWNlIGEgc2NhdHRlciBwbG90IG9mIHRoZSBsb2cgb2YgYnJlYWtpbmcgc3RyZW5ndGggYWdhaW5zdCB0aGUgbG9nIG9mIGRpYW1ldGVyLgoKYGBge3J9CmR0JGxvZ0RpYW0gPC0gbG9nKGR0JGRpYW0pCnBsb3QoZHQkbG9nU3RyZW4sIGR0JGxvZ0RpYW0pCmBgYAoKIyMgNGQgCj4gUmVncmVzcyBicmVha2luZyBzdHJlbmd0aCBvbiBkaWFtZXRlci4gCgpgYGB7cn0KbG0gPC0gbG0oc3RyZW4gfiBkaWFtLCBkYXRhID0gZHQpCmxtCnN1bW1hcnkobG0pCmBgYAoKIyMgNGUKPiBSZWdyZXNzIHRoZSBsb2cgb2YgYnJlYWtpbmcgc3RyZW5ndGggb24gZGlhbWV0ZXIuIAoKYGBge3J9CmxtIDwtIGxtKGxvZ1N0cmVuIH4gZGlhbSwgZGF0YSA9IGR0KQpsbQpzdW1tYXJ5KGxtKQpgYGAKCgojIyA0ZiAKPiBSZWdyZXNzIHRoZSBsb2cgb2YgYnJlYWtpbmcgc3RyZW5ndGggb24gdGhlIGxvZyBvZiBkaWFtZXRlci4gCgpgYGB7cn0KbG0gPC0gbG0obG9nU3RyZW4gfiBsb2dEaWFtLCBkYXRhID0gZHQpCmxtCnN1bW1hcnkobG0pCmBgYAoKIyA1Cj4gRnJvbSB0aGUgZGF0YSBhdmFpbGFibGUgYXQgW2h0dHA6Ly93d3cuc3RhdC51ZmwuZWR1L353aW5uZXIvZGF0YXNldHMuaHRtbF0oaHR0cDovL3d3dy5zdGF0LnVmbC5lZHUvfndpbm5lci9kYXRhc2V0cy5odG1sKSwgb2J0YWluIHRoZSBkYXRhIG9uIOKAnFZhcmlhYmxlcyBhc3NvY2lhdGVkIHdpdGggUGVybWVhYmlsaXR5IGFuZCBQb3Jvc2l0eSBvZiBSb2Nrc+KAnQoKYGBge3J9CmR0IDwtIGZyZWFkKCJyb2Nrcy5jc3YiKQpjb2xuYW1lcyhkdCkgPC0gYygidHlwZSIsICJkZW5zaXR5IiwgInBvcm9zaXR5IiwgImxvZ1Blcm1lYWJpbGl0eSIsICJyZXNpZHVlIiwgImNhcmJvbmF0ZSIsICJhR3JhaW4iLCAiYVNEIiwgImJHcmFpbiIsICJiU0QiLCAiY2FsY2l0ZSIsICJkb2xvbWl0ZSIpCmhlYWQoZHQpCmBgYAoKCiMjIDVhCj4gRml0IGEgbXVsdGlwbGUgcmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IHBvcm9zaXR5LiBQbGVhc2UgcHJvdmlkZSBhIGNsZWFuIG1vZGVsIHdpdGggb25seSBzaWduaWZpY2FudCB2YXJpYWJsZXMuIEludGVycHJldCB5b3VyIG1vZGVsIHJlc3VsdHMgYW5kIGRpYWdub3N0aWNzLgoKYGBge3J9CmxtIDwtIGxtKHBvcm9zaXR5IH4gLiwgZGF0YSA9IGR0KQpsbVN1bW0gPC0gc3VtbWFyeShsbSkKY29lZnMgPC0gY29lZihsbVN1bW0pWy0xLDRdIDw9IC4wNQoKIyBUaGlzIHBydW5lcyB0aGUgcmVncmVzc2lvbiB1bnRpbCBvbmx5IHNpZ25pZmljYW50IHZhcmlhYmxlcyByZW1haW4Kd2hpbGUobGVuZ3RoKGNvZWZzKSAhPSBzdW0oY29lZnMpKSB7CiAgZm9ybSA8LSBwYXN0ZSgicG9yb3NpdHkgfiIsIHBhc3RlKG5hbWVzKGNvZWZzW2NvZWZzXSksICIrIiwgY29sbGFwc2UgPSAiICIpLCBjb2xsYXBzZSA9ICIgIikKICBmb3JtIDwtIHN1YnN0cihmb3JtLCAxLCBuY2hhcihmb3JtKSAtIDIpCiAgZm9ybQogIGxtIDwtIGxtKGZvcm11bGEgPSBmb3JtLCBkYXRhID0gZHQpCiAgbG1TdW1tIDwtIHN1bW1hcnkobG0pCiAgY29lZnMgPC0gY29lZihsbVN1bW0pWy0xLDRdIDw9IC4wNQp9CmxtCmxtU3VtbQpwYXIobWZyb3cgPSBjKDIsMikpCnBsb3QobG0pCmBgYAoKCiMjIDViCj4gRml0IGEgbXVsdGlwbGUgcmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IGxvZyhwZXJtZWFiaWxpdHkpLiBQbGVhc2UgcHJvdmlkZSBhIGNsZWFuIG1vZGVsIHdpdGggb25seSBzaWduaWZpY2FudCB2YXJpYWJsZXMuIEludGVycHJldCB5b3VyIG1vZGVsIHJlc3VsdHMgYW5kIGRpYWdub3N0aWNzLiAgCgpgYGB7cn0KbG0gPC0gbG0obG9nUGVybWVhYmlsaXR5IH4gLiwgZGF0YSA9IGR0KQpsbVN1bW0gPC0gc3VtbWFyeShsbSkKY29lZnMgPC0gY29lZihsbVN1bW0pWy0xLDRdIDw9IC4wNQoKIyBUaGlzIHBydW5lcyB0aGUgcmVncmVzc2lvbiB1bnRpbCBvbmx5IHNpZ25pZmljYW50IHZhcmlhYmxlcyByZW1haW4Kd2hpbGUobGVuZ3RoKGNvZWZzKSAhPSBzdW0oY29lZnMpKSB7CiAgZm9ybSA8LSBwYXN0ZSgibG9nUGVybWVhYmlsaXR5IH4iLCBwYXN0ZShuYW1lcyhjb2Vmc1tjb2Vmc10pLCAiKyIsIGNvbGxhcHNlID0gIiAiKSwgY29sbGFwc2UgPSAiICIpCiAgZm9ybSA8LSBzdWJzdHIoZm9ybSwgMSwgbmNoYXIoZm9ybSkgLSAyKQogIGZvcm0KICBsbSA8LSBsbShmb3JtdWxhID0gZm9ybSwgZGF0YSA9IGR0KQogIGxtU3VtbSA8LSBzdW1tYXJ5KGxtKQogIGNvZWZzIDwtIGNvZWYobG1TdW1tKVstMSw0XSA8PSAuMDUKfQpsbQpsbVN1bW0KcGFyKG1mcm93ID0gYygyLDIpKQpwbG90KGxtKQpgYGAKCg==